package nest2;

import com.symaster.common.geom.entity.Polygon;
import com.symaster.common.geom.entity.Vector;
import com.symaster.common.geom.nest4j.data.*;
import com.symaster.common.geom.nest4j.util.Config;
import com.symaster.common.geom.nest4j.util.NfpUtil;
import com.symaster.common.geom.util.PointUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yinmiao
 * @version 2024/2/29
 */
public class PolygonContainer {

    private final double width;
    private final Config config;
    private final List<NestPath> nestPaths = new ArrayList<>();
    private NestPath containerNestPath;

    public PolygonContainer(double width, Config config) {
        this.width = width;
        this.config = config;
        containerNestPath(null);
    }

    private void containerNestPath(NestPath estimate) {
        final double defaultHeight = 100;

        if (containerNestPath == null) {
            if (nestPaths.isEmpty()) {
                containerNestPath = new Polygon(new double[]{0, width, width, 0}, new double[]{0, 0, defaultHeight, defaultHeight}).toNestPath();
            } else {
                createByItems(estimate);
            }
        } else {

            double useHeight = getUseHeight();
            Bound bound = getBound(containerNestPath);

            double estimateHeight = 0;
            if (estimate != null) {
                Bound bound2 = getBound(estimate);
                estimateHeight = bound2.height;
            }

            // 判断当前底板Path是否够用
            if (useHeight + estimateHeight >= bound.height) {
                // 当前底板Path不够用则重新创建
                createByItems(estimate);
            }
        }
    }

    private void createByItems(NestPath estimate) {
        double useHeight = getUseHeight();
        useHeight *= 1.5;
        if (estimate != null) {
            useHeight += getBound(estimate).height;
        }
        containerNestPath = new Polygon(new double[]{0, width, width, 0}, new double[]{0, 0, useHeight, useHeight}).toNestPath();
    }

    private double getUseHeight() {
        return nestPaths.stream().mapToDouble(e -> {
            Bound bound = getBound(e);
            return bound.ymin + bound.height;
        }).max().orElse(0.0);
    }

    public void add(NestPath nestPath) {
        containerNestPath(nestPath);
        Bound bound = getBound(nestPath);

        if (nestPaths.isEmpty()) {
            nestPaths.add(nestPath);

            // 如果这个是第一次添加则直接放到左上角
            Vector translateVector = PointUtil.getTranslateVector(bound.xmin, bound.ymin, 0, 0);
            offset(nestPath, translateVector.getX(), translateVector.getY());
        } else {

            // 找到当前Y轴的可用线
            double yOffset = nestPaths.stream().mapToDouble(e -> {
                Bound tBound = this.getBound(e);
                return tBound.ymin + tBound.height;
            }).max().orElse(0.0);

            Vector translateVector = PointUtil.getTranslateVector(bound.xmin, bound.ymin, 0, yOffset + 10);
            offset(nestPath, translateVector.getX(), translateVector.getY());

            List<NestPath> nfpList = new ArrayList<>();

            // 先计算当前路径和底板路径的NFP
            NfpPair containerPair = new NfpPair(containerNestPath, nestPath, new NfpKey(containerNestPath.getId(), nestPath.getId(), true, 0, 0));
            ParallelData parallelData2 = NfpUtil.nfpGenerator(containerPair, config);
            if (parallelData2 != null) {
                if (parallelData2.value != null && !parallelData2.value.isEmpty()) {
                    nfpList.addAll(parallelData2.value);
                }
            }

            for (NestPath path : nestPaths) {
                NfpKey key = new NfpKey(path.getId(), nestPath.getId(), false, 0, 0);
                NfpPair pair = new NfpPair(path, nestPath, key);
                ParallelData parallelData = NfpUtil.nfpGenerator(pair, config);
                if (parallelData != null) {
                    if (parallelData.value != null && !parallelData.value.isEmpty()) {
                        nfpList.addAll(parallelData.value);
                    }
                } else {
                    throw new IllegalArgumentException("Nfp 计算出现异常");
                }
            }

            // 获得所有NFP后再计算哪个Nfp可用且最好
            for (NestPath path : nfpList) {

            }
        }
    }

    private void offset(NestPath nestPath, double x, double y) {
        List<Segment> segments = nestPath.getSegments();
        for (Segment segment : segments) {
            segment.x += x;
            segment.y += y;
        }
    }

    private Bound getBound(NestPath nestPath) {

        List<Segment> segments = nestPath.getSegments();

        double x = 0;
        double y = 0;
        double maxX = 0;
        double maxY = 0;

        for (int i = 0; i < segments.size(); i++) {
            Segment segment = segments.get(i);

            if (i == 0) {
                x = segment.x;
                y = segment.y;
                maxX = segment.x;
                maxY = segment.y;
            } else {
                x = Math.min(x, segment.x);
                y = Math.min(y, segment.y);
                maxX = Math.max(maxX, segment.x);
                maxY = Math.max(maxY, segment.y);
            }
        }

        return new Bound(x, y, maxX - x, maxY - y);
    }
}
